package com.alarmtoexercise.alarm;

import com.alarmtoexercise.R;
import com.alarmtoexercise.util.ToastMaster;
import com.alarmtoexercise.util.Tools;

import android.app.TimePickerDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TimePicker;
import android.widget.Toast;

public class SetAlarm extends PreferenceActivity
		implements
			TimePickerDialog.OnTimeSetListener {

	private final static String LOG_CLASS = "SetAlarm";

	private EditTextPreference mLabel;
	private Preference mTimePref;
	private PrefAlarm mAlarmPref;
	private CheckBoxPreference mVibratePref;
	private PrefRepeat mRepeatPref;
	private MenuItem mDeleteAlarmItem;
	private MenuItem mTestAlarmItem;

	private int mId;
	private boolean mEnabled;
	private int mHour;
	private int mMinutes;

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.screen_preferences);
		
		// Add preferences
		addPreferencesFromResource(R.xml.preferences);
				
		// MapUI
		setUI();		
	}
	
	private void setUI() {
		
		findViewById(R.id.ic_add).setVisibility(View.GONE);
		findViewById(R.id.ic_settings).setVisibility(View.GONE);
		
		// Get each preference so we can retrieve the value later.
		mLabel = (EditTextPreference) findPreference("label");
		mLabel.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
			public boolean onPreferenceChange(Preference p, Object newValue) {
				// Set the summary based on the new label.
				p.setSummary((String) newValue);
				return true;
			}
		});
		mTimePref = findPreference("time");
		mAlarmPref = (PrefAlarm) findPreference("alarm");
		mVibratePref = (CheckBoxPreference) findPreference("vibrate");
		mRepeatPref = (PrefRepeat) findPreference("setRepeat");

		Intent i = getIntent();
		mId = i.getIntExtra(AlarmProcessor.ALARM_ID, -1);
		if (Tools.DEBUG) {
			Log.v(LOG_CLASS, "In SetAlarm, alarm id = " + mId);
		}

		/* load alarm details from database */
		AlarmObject alarm = AlarmProcessor.getAlarm(getContentResolver(), mId);
		// Bad alarm, bail to avoid a NPE.
		if (alarm == null) {
			finish();
			return;
		}
		mEnabled = alarm.enabled;
		mLabel.setText(alarm.label);
		mLabel.setSummary(alarm.label);
		mHour = alarm.hour;
		mMinutes = alarm.minutes;
		mRepeatPref.setDaysOfWeek(alarm.daysOfWeek);
		mVibratePref.setChecked(alarm.vibrate);
		// Give the alert uri to the preference.
		mAlarmPref.setAlert(alarm.alert);
		updateTime();

		// We have to do this to get the save/cancel buttons to highlight on
		// their own.
		getListView().setItemsCanFocus(true);

	}

	private void saveAlarm() {
		final String alert = mAlarmPref.getAlertString();
		long time = AlarmProcessor.setAlarm(this, mId, mEnabled, mHour,
				mMinutes, mRepeatPref.getDaysOfWeek(),
				mVibratePref.isChecked(), mLabel.getText(), alert);

		if (mEnabled) {
			popAlarmSetToast(this, time);
		}
	}
	private void updateTime() {
		if (Tools.DEBUG) {
			Log.v(LOG_CLASS, "updateTime " + mId);
		}
		mTimePref.setSummary(AlarmProcessor.formatTime(this, mHour, mMinutes,
				mRepeatPref.getDaysOfWeek()));
	}

	@Override
	public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
			Preference preference) {
		if (preference == mTimePref) {
			new TimePickerDialog(this, this, mHour, mMinutes,
					DateFormat.is24HourFormat(this)).show();
		}

		return super.onPreferenceTreeClick(preferenceScreen, preference);
	}
	/**
	 * Display a toast that tells the user how long until the alarm goes off.
	 * This helps prevent "am/pm" mistakes.
	 */
	static void popAlarmSetToast(Context context, int hour, int minute,
			AlarmObject.DaysOfWeek daysOfWeek) {
		popAlarmSetToast(context,
				AlarmProcessor.calculateAlarm(hour, minute, daysOfWeek)
						.getTimeInMillis());
	}

	private static void popAlarmSetToast(Context context, long timeInMillis) {
		String toastText = formatToast(context, timeInMillis);
		Toast toast = Toast.makeText(context, toastText, Toast.LENGTH_LONG);
		ToastMaster.setToast(toast);
		toast.show();
	}

	/**
	 * format "Alarm set for 2 days 7 hours and 53 minutes from now"
	 */
	static String formatToast(Context context, long timeInMillis) {
		long delta = timeInMillis - System.currentTimeMillis();
		long hours = delta / (1000 * 60 * 60);
		long minutes = delta / (1000 * 60) % 60;
		long days = hours / 24;
		hours = hours % 24;

		String daySeq = (days == 0) ? "" : (days == 1) ? context
				.getString(R.string.day) : context.getString(R.string.days,
				Long.toString(days));

		String minSeq = (minutes == 0) ? "" : (minutes == 1) ? context
				.getString(R.string.minute) : context.getString(
				R.string.minutes, Long.toString(minutes));

		String hourSeq = (hours == 0) ? "" : (hours == 1) ? context
				.getString(R.string.hour) : context.getString(R.string.hours,
				Long.toString(hours));

		boolean dispDays = days > 0;
		boolean dispHour = hours > 0;
		boolean dispMinute = minutes > 0;

		int index = (dispDays ? 1 : 0) | (dispHour ? 2 : 0)
				| (dispMinute ? 4 : 0);

		String[] formats = context.getResources().getStringArray(
				R.array.alarm_set);
		return String.format(formats[index], daySeq, hourSeq, minSeq);
	}

	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);

		mDeleteAlarmItem = menu.add(0, 0, 0, R.string.delete_alarm);
		mDeleteAlarmItem.setIcon(android.R.drawable.ic_menu_delete);

		if (Tools.DEBUG) {
			mTestAlarmItem = menu.add(0, 0, 0, "test alarm");
		}

		return true;
	}

	public boolean onOptionsItemSelected(MenuItem item) {
		if (item == mDeleteAlarmItem) {
			AlarmProcessor.deleteAlarm(this, mId);
			finish();
			return true;
		}
		if (Tools.DEBUG) {
			if (item == mTestAlarmItem) {
				setTestAlarm();
				return true;
			}
		}

		return false;
	}

	@Override
	public void onBackPressed() {
		saveAlarm();
		finish();
	}

	public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
		mHour = hourOfDay;
		mMinutes = minute;
		updateTime();
		// If the time has been changed, enable the alarm.
		mEnabled = true;
	}

	/**
	 * Write alarm out to persistent store and pops toast if alarm enabled. Used
	 * only in test code.
	 */
	private static void saveAlarm(Context context, int id, boolean enabled,
			int hour, int minute, AlarmObject.DaysOfWeek daysOfWeek,
			boolean vibrate, String label, String alert, boolean popToast) {
		if (Tools.DEBUG)
			Log.v(LOG_CLASS, "** saveAlarm " + id + " " + label + " " + enabled
					+ " " + hour + " " + minute + " vibe " + vibrate);

		// Fix alert string first
		long time = AlarmProcessor.setAlarm(context, id, enabled, hour, minute,
				daysOfWeek, vibrate, label, alert);

		if (enabled && popToast) {
			popAlarmSetToast(context, time);
		}
	}

	/**
	 * Test code: this is disabled for production build. Sets this alarm to go
	 * off on the next minute
	 */
	void setTestAlarm() {

		// start with now
		java.util.Calendar c = java.util.Calendar.getInstance();
		c.setTimeInMillis(System.currentTimeMillis());

		int nowHour = c.get(java.util.Calendar.HOUR_OF_DAY);
		int nowMinute = c.get(java.util.Calendar.MINUTE);

		int minutes = (nowMinute + 1) % 60;
		int hour = nowHour + (nowMinute == 0 ? 1 : 0);

		saveAlarm(this, mId, true, hour, minutes, mRepeatPref.getDaysOfWeek(),
				true, mLabel.getText(), mAlarmPref.getAlertString(), true);
	}
}
